/****************************************************************************

 Copyright (C) 2002-2007 Gilles Debunne (Gilles.Debunne@imag.fr)

 This file is part of the QGLViewer library.
 Version 2.3.0, released on June 29, 2008.

 http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer

 libQGLViewer is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 libQGLViewer is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with libQGLViewer; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*****************************************************************************/

#include "simpleViewer.h"
using namespace std;
using namespace MeshUtils;

// Draws a spiral
void Viewer::draw()
{
  const float nbSteps = 200.0;

	glPushMatrix ();


	drawScene(&(Viewer::setMat));

	//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	glPopMatrix();
}

void Viewer::drawTriangles(ptToSetMat setMatp, void* matArg, std::vector<Vector3>& nodes, std::vector<Face_t> faces)
{
	for(vector<Face_t>::iterator fIt = faces.begin() ; fIt != faces.end() ; fIt++)
	{
		const Vector3& a = nodes[fIt->A];
		const Vector3& b = nodes[fIt->B];
		const Vector3& c = nodes[fIt->C];

        Vector3 n = (b - a) ^ (c - a);
        n.normalize();

		//glColor3f(1.0, 0.0, 0.0);
		(*setMatp)(matArg);
		glNormal3f(n.x, n.y, n.z);glVertex3f(a.x, a.y, a.z);
		glNormal3f(n.x, n.y, n.z);glVertex3f(b.x, b.y, b.z);
		glNormal3f(n.x, n.y, n.z);glVertex3f(c.x, c.y, c.z);


		//If the previous triangle was badly orentated, it will be culled. Therefore we add a new triangle with inverse node ordering and inverse normal.
		//Inversely, if the previous triangle was not culled, this one will be !
		//glColor3f(1.0, 0.0, 0.0);
		(*setMatp)(matArg);
		glNormal3f(-n.x, -n.y, -n.z);glVertex3f(a.x, a.y, a.z);
		glNormal3f(-n.x, -n.y, -n.z);glVertex3f(c.x, c.y, c.z);
		glNormal3f(-n.x, -n.y, -n.z);glVertex3f(b.x, b.y, b.z);
    }
}

void Viewer::drawShrinkedTriangles(ptToSetMat setMatp, std::vector<Vector3>& nodes, std::vector<Face_t> faces, const double shrinkFactor)
{
	for(vector<Face_t>::iterator fIt = faces.begin() ; fIt != faces.end() ; fIt++)
	{
		const Vector3& a = nodes[fIt->A];
		const Vector3& b = nodes[fIt->B];
		const Vector3& c = nodes[fIt->C];

        Vector3 n = (b - a) ^ (c - a); n.normalize();

        Vector3 centroid = (a + b + c) * (1.0/3.0);
        Vector3 aa = a - (a - centroid) * shrinkFactor;
        Vector3 bb = b - (b - centroid) * shrinkFactor;
        Vector3 cc = c - (c - centroid) * shrinkFactor;


		glColor3f(1.0, 0.0, 0.0);
		(*setMatp)(NULL);
		glNormal3f(n.x, n.y, n.z);glVertex3f(aa.x, aa.y, aa.z);
		glNormal3f(n.x, n.y, n.z);glVertex3f(bb.x, bb.y, bb.z);
		glNormal3f(n.x, n.y, n.z);glVertex3f(cc.x, cc.y, cc.z);


		//If the previous triangle was badly orentated, it will be culled. Therefore we add a new triangle with inverse node ordering and inverse normal.
		//Inversely, if the previous triangle was not culled, this one will be !
		glColor3f(1.0, 0.0, 0.0);
		(*setMatp)(NULL);
		glNormal3f(-n.x, -n.y, -n.z);glVertex3f(aa.x, aa.y, aa.z);
		glNormal3f(-n.x, -n.y, -n.z);glVertex3f(cc.x, cc.y, cc.z);
		glNormal3f(-n.x, -n.y, -n.z);glVertex3f(bb.x, bb.y, bb.z);
    }
}

void Viewer::drawTetrahedra(ptToSetMat setMatp, void* matArg, Mesh& mesh, const double shrinkFactor)
{
	for(vector<MeshUtils::Element>::iterator eIt = mesh.elts.begin() ; eIt != mesh.elts.end() ; eIt++)
	{
		 Vector3 centroid = (mesh.nodes[eIt->nodesList[0]] + mesh.nodes[eIt->nodesList[1]] + mesh.nodes[eIt->nodesList[2]] + mesh.nodes[eIt->nodesList[3]]) * 0.25;

		 Vector3 a = mesh.nodes[eIt->nodesList[0]] - (mesh.nodes[eIt->nodesList[0]] - centroid) * shrinkFactor;
		 Vector3 b = mesh.nodes[eIt->nodesList[1]] - (mesh.nodes[eIt->nodesList[1]] - centroid) * shrinkFactor;
		 Vector3 c = mesh.nodes[eIt->nodesList[2]] - (mesh.nodes[eIt->nodesList[2]] - centroid) * shrinkFactor;
		 Vector3 d = mesh.nodes[eIt->nodesList[3]] - (mesh.nodes[eIt->nodesList[3]] - centroid) * shrinkFactor;

		 //////////
		 //FACE 1//
		 //////////
		 Vector3 n = (b - a) ^ (c - a); n.normalize();
		 //glColor3f(1.0, 0.0, 0.0);
		 (*setMatp)(matArg);
		 glNormal3f(n.x, n.y, n.z);glVertex3f(a.x, a.y, a.z);
		 glNormal3f(n.x, n.y, n.z);glVertex3f(b.x, b.y, b.z);
		 glNormal3f(n.x, n.y, n.z);glVertex3f(c.x, c.y, c.z);
		 //If the previous triangle was badly orentated, it will be culled. Therefore we add a new triangle with inverse node ordering and inverse normal.
		 //Inversely, if the previous triangle was not culled, this one will be !
		 //glColor3f(1.0, 0.0, 0.0);
		 (*setMatp)(matArg);
		 glNormal3f(-n.x, -n.y, -n.z);glVertex3f(a.x, a.y, a.z);
		 glNormal3f(-n.x, -n.y, -n.z);glVertex3f(c.x, c.y, c.z);
		 glNormal3f(-n.x, -n.y, -n.z);glVertex3f(b.x, b.y, b.z);

		 //////////
		 //FACE 2//
		 //////////
		 n = (b - a) ^ (d - a); n.normalize();
		 //glColor3f(1.0, 0.0, 0.0);
		 (*setMatp)(matArg);
		 glNormal3f(n.x, n.y, n.z);glVertex3f(a.x, a.y, a.z);
		 glNormal3f(n.x, n.y, n.z);glVertex3f(b.x, b.y, b.z);
		 glNormal3f(n.x, n.y, n.z);glVertex3f(d.x, d.y, d.z);
		 //If the previous triangle was badly orentated, it will be culled. Therefore we add a new triangle with inverse node ordering and inverse normal.
		 //Inversely, if the previous triangle was not culled, this one will be !
		 //glColor3f(1.0, 0.0, 0.0);
		 (*setMatp)(matArg);
		 glNormal3f(-n.x, -n.y, -n.z);glVertex3f(a.x, a.y, a.z);
		 glNormal3f(-n.x, -n.y, -n.z);glVertex3f(d.x, d.y, d.z);
		 glNormal3f(-n.x, -n.y, -n.z);glVertex3f(b.x, b.y, b.z);

		 //////////
		 //FACE 3//
		 //////////
		 n = (d - a) ^ (c - a); n.normalize();
		 //glColor3f(1.0, 0.0, 0.0);
		 (*setMatp)(matArg);
		 glNormal3f(n.x, n.y, n.z);glVertex3f(a.x, a.y, a.z);
		 glNormal3f(n.x, n.y, n.z);glVertex3f(d.x, d.y, d.z);
		 glNormal3f(n.x, n.y, n.z);glVertex3f(c.x, c.y, c.z);
		 //If the previous triangle was badly orentated, it will be culled. Therefore we add a new triangle with inverse node ordering and inverse normal.
		 //Inversely, if the previous triangle was not culled, this one will be !
		 //glColor3f(1.0, 0.0, 0.0);
		 (*setMatp)(matArg);
		 glNormal3f(-n.x, -n.y, -n.z);glVertex3f(a.x, a.y, a.z);
		 glNormal3f(-n.x, -n.y, -n.z);glVertex3f(c.x, c.y, c.z);
		 glNormal3f(-n.x, -n.y, -n.z);glVertex3f(d.x, d.y, d.z);

		  //////////
		 //FACE 4//
		 //////////
		 n = (c - b) ^ (d - b); n.normalize();
		 //glColor3f(1.0, 0.0, 0.0);
		 (*setMatp)(matArg);
		 glNormal3f(n.x, n.y, n.z);glVertex3f(b.x, b.y, b.z);
		 glNormal3f(n.x, n.y, n.z);glVertex3f(c.x, c.y, c.z);
		 glNormal3f(n.x, n.y, n.z);glVertex3f(d.x, d.y, d.z);
		 //If the previous triangle was badly orentated, it will be culled. Therefore we add a new triangle with inverse node ordering and inverse normal.
		 //Inversely, if the previous triangle was not culled, this one will be !
		 //glColor3f(1.0, 0.0, 0.0);
		 (*setMatp)(matArg);
		 glNormal3f(-n.x, -n.y, -n.z);glVertex3f(b.x, b.y, b.z);
		 glNormal3f(-n.x, -n.y, -n.z);glVertex3f(d.x, d.y, d.z);
		 glNormal3f(-n.x, -n.y, -n.z);glVertex3f(c.x, c.y, c.z);

	}
}

void Viewer::setMat(void* arg)
{
    if(MatInfo* mi = static_cast<MatInfo*>(arg))
    {
        Material mat = mi->This->scnMng.getMaterial(string(mi->name));
        glColor4ub(mat.R, mat.G, mat.B, mat.A);
    }
};


void Viewer::drawRec(SceneNode& root, SceneManager& scnMng, MeshManager& mshMng)
{
    static map<string, unsigned int> loaded;
	string entName = root.getEntityName();
	try {
        Entity& ent = scnMng.getEntity(entName);
        Mesh& mesh = mshMng.getMesh(ent.meshName);
        glPushMatrix();
        glTranslatef(root.getPosition().x, root.getPosition().y, root.getPosition().z);

        MatInfo mi;
        mi.This = this;
        mi.name = ent.materialName.c_str();

        if(this->drawTets)
        {
            glPolygonMode(GL_FRONT, GL_FILL);
            glPolygonMode(GL_BACK, GL_FILL);
            glBegin(GL_TRIANGLES);
            glMatrixMode(GL_MODELVIEW);
            this->drawTetrahedra(&(Viewer::setMat), &mi, mesh, 0.2);
            glEnd();
            glPopMatrix();
        }
        else
        {
            unsigned int i = loaded[ent.meshName];
            if(!i)
            {
                static int lIdx = 0;

                glPolygonMode(GL_FRONT, GL_FILL);
                glPolygonMode(GL_BACK, GL_FILL);
                glNewList(index+lIdx, GL_COMPILE);
                glBegin(GL_TRIANGLES);
                glMatrixMode(GL_MODELVIEW);
                this->drawTriangles(&(Viewer::setMat), &mi, mesh.nodes, mesh.faces);
                glEnd();
                glPopMatrix();
                glEndList();
                glCallList(index+lIdx++);
                loaded[ent.meshName] = lIdx;
            }
            else if(update)
            {
                cout << "redraw triangles" << endl;
                int lIdx = i;

                glPolygonMode(GL_FRONT, GL_FILL);
                glPolygonMode(GL_BACK, GL_FILL);
                glNewList(index+lIdx, GL_COMPILE);
                glBegin(GL_TRIANGLES);
                glMatrixMode(GL_MODELVIEW);
                this->drawTriangles(&(Viewer::setMat), &mi, mesh.nodes, mesh.faces);
                glEnd();
                glPopMatrix();
                glEndList();
                glCallList(index+lIdx++);
                loaded[ent.meshName] = lIdx;
            }
            else
            {
                glCallList(index + i-1);
            }
      }


    } catch (...)
    {
        //cout << "no mesh associated with this node" << endl;
    }
    int i = 0;
	for(std::vector<SceneNode*>::iterator cIt = root.childs.begin() ; cIt != root.childs.end() ; cIt++)
	{
        drawRec(*(*cIt), scnMng, mshMng);
    }
    update = false;
}

void Viewer::drawScene(ptToSetMat setMatp)
{
	drawRec(scnMng.getRoot(), scnMng, mshMng);
}

void Viewer::addMesh(Mesh& msh, string name)
{
	mshMng.addMesh(msh, name);
}

Entity& Viewer::createEntity(string name, string mshName, string matName)
{
	return scnMng.createEntity(name, mshName,  matName);
}

// Should be generalized for any node, not only root
void Viewer::linkEntityToRoot(string name)
{
	scnMng.getRoot().linkEntity(name);
}
SceneNode&  Viewer::getRoot()
{
	return scnMng.getRoot();
}


void  Viewer::addMaterial(const Material m, string name)
{
	scnMng.addMaterial(m, name);
}


void Viewer::init()
{
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // Light0 is the default ambient light
    glEnable(GL_LIGHT0);


    // Light1 is a spot light
    //glEnable(GL_LIGHT1);
    const GLfloat light_ambient[4]  = {0.8f, 0.2f, 0.2f, 1.0};
    const GLfloat light_diffuse[4]  = {1.0, 0.4f, 0.4f, 1.0};
    const GLfloat light_specular[4] = {1.0, 0.0, 0.0, 1.0};

    glLightf( GL_LIGHT1, GL_SPOT_EXPONENT,  1.0);
    glLightf( GL_LIGHT1, GL_SPOT_CUTOFF,    5.0);
    glLightf( GL_LIGHT1, GL_CONSTANT_ATTENUATION, 0.5);
    glLightf( GL_LIGHT1, GL_LINEAR_ATTENUATION, 1.0);
    glLightf( GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 1.5);
    //glLightfv(GL_LIGHT1, GL_AMBIENT,  light_ambient);
    glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular);
    glLightfv(GL_LIGHT1, GL_DIFFUSE,  light_diffuse);

    glEnable(GL_CULL_FACE); //remove badly orientated face. Based on node order.  a b c  != a c b
	//glEnable(GL_COLOR_MATERIAL);

    //add transparency support using blending
    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


    index = glGenLists(10);  // create 10 display lists
    cout << "list index : " << index << endl;


	unsigned int w = 800;
    unsigned int h = 600;



	console = new Console(this);
	//Add console to BaijiAccesor to use it from lua.
    //Theses init lust be done before console->init
	BaijiAccessor::setConsole(*console);
	BaijiAccessor::setMeshManager(mshMng);
    console->init();




    console->setEnabled(true);
	console->setVisible(false);
    // Restore previous viewer state.
    restoreStateFromFile();



  // Opens help window
 // help();
}

void Viewer::keyPressEvent(QKeyEvent *e)
{
	bool handled = false;
    static int smooth = false;
  // A simple switch on e->key() is not sufficient if we want to take state key into account.
  // With a switch, it would have been impossible to separate 'F' from 'CTRL+F'.
  // That's why we use imbricated if...else and a "handled" boolean.
  if ((e->key()==Qt::Key_T))
	{
		drawTets = !drawTets;
        update = true;
		updateGL();
		handled = true;
	}

	if ((e->key()==Qt::Key_W))
	{
		string entName("duck");// = scnMng.getRoot().getEntityName();
		Entity& ent = scnMng.getEntity(entName);
		Mesh& mesh = mshMng.getMesh(ent.meshName);
		mesh.subdivide();
		updateGL();
		handled = true;
	}
	if ((e->key()==Qt::Key_I))
	{
	    smooth = ! smooth;
    }


	if ((e->key()==Qt::Key_D))
	{
        const  char* target = "/home/kayhman/myApp/baiji/mesh/kitten.obj";
        ObjParser parser(target);
        std::vector<MeshUtils::Vector3> nodes;
        std::vector<MeshUtils::Vector3> normals;
        std::vector<MeshUtils::Vector3> textures;
        std::vector<MeshUtils::Face_t> faces;
        unsigned int nbNodes;
        unsigned int nbNorms;
        unsigned int nbFaces;

        static Mesh* targetMesh = NULL;
        if(!targetMesh)
        {
            targetMesh = new Mesh();;
            parser.load(targetMesh->nodes, normals, textures,  targetMesh->faces,  nbNodes, nbNorms, nbFaces);


            Material m;
            m.G = 255;
            m.A = 125;
            this->addMaterial(m, "targetMaterial");

            this->addMesh(*targetMesh, "targetMesh");
            SceneNode& child = this->getRoot().createChild();
            this->createEntity("duckTarget", "targetMesh", "targetMaterial");
            child.linkEntity("duckTarget");
		}
        updateGL();
		handled = true;
	}


	if ((e->key()==Qt::Key_O))
	{
        const  char* target = "/home/kayhman/myApp/baiji/mesh/kitten.obj";
        /*
        ObjParser parser(target);
        std::vector<MeshUtils::Vector3> nodes;
        std::vector<MeshUtils::Vector3> normals;
        std::vector<MeshUtils::Vector3> textures;
        std::vector<MeshUtils::Face_t> faces;
        unsigned int nbNodes;
        unsigned int nbNorms;
        unsigned int nbFaces;

        static Mesh* targetMesh = NULL;
        if(!targetMesh)
        {
            new Mesh();;
            parser.load(targetMesh->nodes, normals, textures,  targetMesh->faces,  nbNodes, nbNorms, nbFaces);


            Material m;
            m.G = 255;
            m.A = 125;
            this->addMaterial(m, "targetMaterial");

            this->addMesh(*targetMesh, "targetMesh");
            SceneNode& child = this->getRoot().createChild();
            this->createEntity("duckTarget", "targetMesh", "targetMaterial");
            child.linkEntity("duckTarget");
		}*/
            string entName("duck");// = scnMng.getRoot().getEntityName();
            Entity& ent = scnMng.getEntity(entName);
            Mesh& mesh = mshMng.getMesh(ent.meshName);
        if(!drawTets)
            for(unsigned int i = 0 ; i < 1 ; i++)
             {
                mesh.optimizeTriangles(target, smooth);
                update = true;
                updateGL();
		    }
        else
        {
            map<unsigned int, bool> isOnBoundary;
            for(map<unsigned int, unsigned int>::iterator mit = mesh.nodesMapBToV.begin() ; mit !=  mesh.nodesMapBToV.end() ; mit++)
                isOnBoundary[mit->second] = true;

            for(unsigned int i = 0 ; i < 1 ; i++)
            {
                mesh.optimizeTetras(target, smooth);
                update = true;
                updateGL();
               //Ouput nodes for tetgen
                stringstream ss2;
                ss2 << "newMesh" << i << ".node";
               
                ofstream outNode(ss2.str().c_str());
                outNode << mesh.nodes.size() << " 3 0 0" <<endl;
                for(unsigned int n = 0 ; n < mesh.nodes.size() ; n++)
                    outNode << n << " " << mesh.nodes[n].x << " " << mesh.nodes[n].y << " " << mesh.nodes[n].z << endl;
                outNode.close();

                //Ouput elements for tetgen
                stringstream ss3;
                ss3 << "newMesh" << i << ".ele";
                ofstream outTet(ss3.str().c_str());
                unsigned int nbTet = 0;
                
                for(unsigned int t = 0 ; t < mesh.elts.size() ; t++)
                {
                    unsigned int n0 = mesh.elts[t].nodesList[0];
                    unsigned int n1 = mesh.elts[t].nodesList[1];
                    unsigned int n2 = mesh.elts[t].nodesList[2];
                    unsigned int n3 = mesh.elts[t].nodesList[3];
                    //if(isOnBoundary[n0] + isOnBoundary[n1]  + isOnBoundary[n2] + isOnBoundary[n3] < 3)
                        nbTet++;
                }
                outTet << nbTet << " 4 0" << endl;
                nbTet = 0;
                for(unsigned int t = 0 ; t < mesh.elts.size() ; t++)
                {
                    unsigned int n0 = mesh.elts[t].nodesList[0];
                    unsigned int n1 = mesh.elts[t].nodesList[1];
                    unsigned int n2 = mesh.elts[t].nodesList[2];
                    unsigned int n3 = mesh.elts[t].nodesList[3];
                    //if(isOnBoundary[n0] + isOnBoundary[n1]  + isOnBoundary[n2] + isOnBoundary[n3] < 3)
                        outTet << nbTet++ << " " <<  mesh.elts[t].nodesList[0] << " " << mesh.elts[t].nodesList[1] << " " << mesh.elts[t].nodesList[2] << " " << mesh.elts[t].nodesList[3] << endl;
                }
                outTet.close();
            }
     //mesh.computeBoundary();
        }
        update = true;
        updateGL();
		handled = true;
	}

	if ((e->key()==Qt::Key_C))
	{
		static bool doShow = true;

		if(doShow)
        {
			//console->getTextBox()->show();
			console->show();
        }
        else
        {
			//console->getTextBox()->hide();
        	console->hide();
        }
		doShow = !doShow;
		handled = true;
	}

	if ((e->key()==Qt::Key_P))
	{
		string entName("duck");// = scnMng.getRoot().getEntityName();
		Entity& ent = scnMng.getEntity(entName);
		Mesh& mesh = mshMng.getMesh(ent.meshName);
        
        std::vector<MeshUtils::Vector3> nodes;
        std::vector<Face_t> faces;

        mesh.getBoundary(nodes, faces);
        static int i = 0;
        stringstream ss;
        ss << "newMesh" << i << ".obj";
		ofstream out(ss.str().c_str());
		for(unsigned int n = 0 ; n < mesh.nodesMapBToV.size() ; n++)
			out << "v " << nodes[n].x << " " << nodes[n].y << " " << nodes[n].z << endl;


		for(unsigned int f = 0 ; f < faces.size() ; f++)
			out << "f " << faces[f].A+1 << " " << faces[f].B+1 << " " << faces[f].C+1 << endl;

		out.close();
        
        cout << "mesh ouput has " << ss.str() << endl;
        

        //Ouput nodes for tetgen
        stringstream ss2;
        ss2 << "newMesh" << i << ".node";
       
		ofstream outNode(ss2.str().c_str());
		outNode << mesh.nodes.size() << " 3 0 0" <<endl;
		for(unsigned int n = 0 ; n < mesh.nodes.size() ; n++)
			outNode << n << " " << mesh.nodes[n].x << " " << mesh.nodes[n].y << " " << mesh.nodes[n].z << endl;
		outNode.close();

        //Ouput elements for tetgen
        stringstream ss3;
        ss3 << "newMesh" << i++ << ".ele";
		ofstream outTet(ss3.str().c_str());
		outTet << mesh.elts.size() << " 4 0" << endl;
		for(unsigned int t = 0 ; t < mesh.elts.size() ; t++)
			outTet << t << " " <<  mesh.elts[t].nodesList[0] << " " << mesh.elts[t].nodesList[1] << " " << mesh.elts[t].nodesList[2] << " " << mesh.elts[t].nodesList[3] << endl;

		outTet.close();

        handled = true;
	}


  if (!handled)
  {
    QGLViewer::keyPressEvent(e);
  }
}


void Viewer::drawRecInSelectionMode(SceneNode& root, SceneManager& scnMng, MeshManager& mshMng)
{
	static int nameIdx = 0;

	string entName = root.getEntityName();
	Entity& ent = scnMng.getEntity(entName);
	Mesh& mesh = mshMng.getMesh(ent.meshName);
	glPushMatrix();
	glTranslatef(root.getPosition().x, root.getPosition().y, root.getPosition().z);

	glPushName(nameIdx);
	glBegin(GL_TRIANGLES);
	if(this->drawTets)
	{
		glMatrixMode(GL_MODELVIEW);
		glPolygonMode(GL_FRONT, GL_FILL);
		glPolygonMode(GL_BACK, GL_FILL);
		this->drawTetrahedra(&(Viewer::setMat), NULL, mesh, 0.2);
	}
	else
	{
		glMatrixMode(GL_MODELVIEW);
		glPolygonMode(GL_FRONT, GL_FILL);
		glPolygonMode(GL_BACK, GL_FILL);
		this->drawTriangles(&(Viewer::setMat), NULL, mesh.nodes, mesh.faces);
	}

	glPopName();

	glEnd();
	glPopMatrix();

	for(std::vector<SceneNode*>::iterator cIt = root.childs.begin() ; cIt != root.childs.end() ; cIt++)
		drawRecInSelectionMode(*(*cIt), scnMng, mshMng);
}

void Viewer::drawWithNames()
{
	drawRecInSelectionMode(scnMng.getRoot(), scnMng, mshMng);
}

void Viewer::postSelection(const QPoint& point)
{


  if (selectedName() == -1)
    QMessageBox::information(this, "No selection",
			     "No object selected under pixel " + QString::number(point.x()) + "," + QString::number(point.y()));
  else
    QMessageBox::information(this, "Selection",
			     "Spiral number " + QString::number(selectedName()) + " selected under pixel " +
			     QString::number(point.x()) + "," + QString::number(point.y()));
}

void Viewer::select(const QPoint & point)
{
	cout << "selection start" << endl;
	beginSelection(point);
	drawWithNames();
	endSelection(point);
	postSelection(point);
}


QString Viewer::helpString() const
{
  QString text("<h2>S i m p l e V i e w e r</h2>");
  text += "Use the mouse to move the camera around the object. ";
  text += "You can respectively revolve around, zoom and translate with the three mouse buttons. ";
  text += "Left and middle buttons pressed together rotate around the camera view direction axis<br><br>";
  text += "Pressing <b>Alt</b> and one of the function keys (<b>F1</b>..<b>F12</b>) defines a camera keyFrame. ";
  text += "Simply press the function key again to restore it. Several keyFrames define a ";
  text += "camera path. Paths are saved when you quit the application and restored at next start.<br><br>";
  text += "Press <b>F</b> to display the frame rate, <b>A</b> for the world axis, ";
  text += "<b>Alt+Return</b> for full screen mode and <b>Control+S</b> to save a snapshot. ";
  text += "See the <b>Keyboard</b> tab in this window for a complete shortcut list.<br><br>";
  text += "Double clicks automates single click actions: A left button double click aligns the closer axis with the camera (if close enough). ";
  text += "A middle button double click fits the zoom of the camera and the right button re-centers the scene.<br><br>";
  text += "A left button double click while holding right button pressed defines the camera <i>Revolve Around Point</i>. ";
  text += "See the <b>Mouse</b> tab and the documentation web pages for details.<br><br>";
  text += "Press <b>Escape</b> to exit the viewer.";
  return text;
}
